<?php

/**
 * @name   序列化调研
 * @author Rohn(253133755@qq.com)
 * @date   2017/7/6
 */
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/proto/Test.php';

class SerializeTest
{

    private $test_data = array();
    private $data_json = array();
    private $data_pb = array();

    public $report = array();

    static $str = array(
        'a',
        'b',
        'c',
        'd',
        'e',
        'f',
        'g',
        'h',
        'i',
        'j',
        'k',
        'l',
        'm',
        'n',
        'o',
        'p',
        'q',
        'r',
        's',
        't',
        'u',
        'v',
        'w',
        'x',
        'y',
        'z',
        'A',
        'B',
        'C',
        'D',
        'E',
        'F',
        'G',
        'H',
        'I',
        'J',
        'K',
        'L',
        'M',
        'N',
        'O',
        'P',
        'Q',
        'R',
        'S',
        'T',
        'U',
        'V',
        'W',
        'X',
        'Y',
        'Z',
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        0,
        '_',
        '!',
        '@',
        '#',
        '$',
        '%',
        '^',
        '&',
        '*',
        '(',
        ')',
        '-',
        '+',
        '=',
        '阿',
        '萨',
        '德',
        '额',
        '人',
        '哦',
        '吗',
        '从',
        '是',
        '去',
        '吧',
        '你',
        '放',
        '如',
    );
    protected $count;

    /**
     * 运行入口
     */
    public function run(){

        $list = array(
            10,
            100,
            1000,
            3000,
            30000,
            100000,
            300000,
        );
        foreach($list as $test){
         
            $this->_do_run($test);
        }
        print_r($this->report);
    }

    /**
     * 运行测试数据
     * @param $count
     */
    private function _do_run($count){

        $this->_get_data($count);
        $encode_report  = $this->_encode();
        $decode_report  = $this->_decode();
        
        $this->report[] = array_merge(['长度'=>$count],$encode_report, $decode_report);
    }

    /**
     * 序列化
     * @return array
     */
    private function _encode(){

        //json
        $this->data_json  = null;
        $s_mem            = memory_get_usage();
        $s_time           = microtime(true);
        $this->data_json  = json_encode($this->test_data);
        $e_time           = microtime(true);
        $e_mem            = memory_get_usage();
        $length_json      = number_format(mb_strlen($this->data_json) / 1024, 7, '.', '');
        $encode_meme_json = $e_mem - $s_mem;
        $encode_time_json = $e_time - $s_time;

        //protobuf
        $test_obj      = new Test();
        $this->data_pb = null;
        $test_obj->setAaa($this->test_data['aaa']);
        if(isset($this->test_data['bbb']) && count($this->test_data['bbb']) > 0){
            foreach($this->test_data['bbb'] as $b){
                $old = $test_obj->getBbb();
             
                $old[]=$b;
//                var_dump($old);
                $test_obj->setBbb($old);
            }
        }
        $s_mem          = memory_get_usage();
        $s_time         = microtime(true);
        $this->data_pb  = $test_obj->serializeToString();
        $e_time         = microtime(true);
        $e_mem          = memory_get_usage();
        $length_pb      = number_format(mb_strlen($this->data_pb) / 1024, 7, '.', '');
        $encode_meme_pb = $e_mem - $s_mem;
        $encode_time_pb = $e_time - $s_time;
        $test_obj       = null;

        return array(
            'js长度'      => $length_json,
            'pb长度'      => $length_pb,
            'json比pb长百分比'       => ($length_json - $length_pb) * 100 / $length_pb,
            '编码_mem_js'  => $encode_meme_json,
            '编码_mem_pb'  => $encode_meme_pb,
            'json比pb编码多耗内存百分比'   => ($encode_meme_json - $encode_meme_pb) * 100 / $encode_meme_pb,
            '编码_time_js' => $encode_time_json,
            '编码_time_pb' => $encode_time_pb,
            'json比pb编码多耗时间百分比'  => ($encode_time_json - $encode_time_pb) * 100 / $encode_time_pb,
        );
    }

    /**
     * 解序列化
     * @return array
     */
    private function _decode(){

        //json
        $s_mem            = memory_get_usage();
        $s_time           = microtime(true);
        $d                = json_decode($this->data_json, 1);
        $e_time           = microtime(true);
        $e_mem            = memory_get_usage();
        $decode_meme_json = $e_mem - $s_mem;
        $decode_time_json = $e_time - $s_time;
        $d                = null;

        //protobuf
        $test_obj = new Test();
        $s_mem    = memory_get_usage();
        $s_time   = microtime(true);
        $test_obj->mergeFromString($this->data_pb);
        $e_time         = microtime(true);
        $e_mem          = memory_get_usage();
        $decode_meme_pb = $e_mem - $s_mem;
        $decode_time_pb = $e_time - $s_time;
        $test_obj       = null;

        return array(
            '解码_mem_js'  => $decode_meme_json,
            '解码_mem_pb'  => $decode_meme_pb,
            'JSON比pb解码多消耗内存百分比'   => ($decode_meme_json - $decode_meme_pb) * 100 / $decode_meme_pb,
            '解码_time_js' => $decode_time_json,
            '解码_time_pb' => $decode_time_pb,
            'JSON比pb解码多消耗时间百分比'  => ($decode_time_json - $decode_time_pb) * 100 / $decode_time_pb,
        );
    }

    /**
     * 构造数据
     * @param $count
     */
    private function _get_data($count){

        $this->test_data['aaa'] = mt_rand(0, $count);
        for($i = 0; $i < $count; $i++){
            $this->test_data['bbb'][] = $this->get_str(100);
        }
    }

    /**
     * 获得随机字符串
     * @param $length
     * @return string
     */
    private function get_str($length){

        $data  = '';
        $count = count(self::$str);
        for($i = 0; $i < $length; $i++){
            $data .= self::$str[mt_rand(0, $count - 1)];
        }

        return $data;
    }
}
ini_set('memory_limit', '2048M');
$s = new SerializeTest();
$s->run();

